<?php
/**
* @package nl.millipede.parser.template.ectemplate
* @version v2
* @author Jeroen Olthof <j.olthof@millipede.nl>
*
* Company millipede (www.millipede.nl)
* 
* EcTemplate home : http://www.millipede.nl/ectemplate/
* 
* This program is free software; you can redistribute it and/or modify it under
* the GNU Library General Public License, with the following stipulations;
* 
* Changes or modifications must retain these Copyright statements.
* Changes or modifications must be submitted to both AUTHOR.
* 
* This program is released under the GNU Library General Public License.
* ( http://www.gnu.org/copyleft/lgpl.html )
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS

* PHP Version Copyright (c) 2001 Millipede,
* ectemplate@millipede.nl, All Rights Reserved.
*/
class EcTemplate2 
{

/**
* ecTemplate version.
*
* Just for showing the version in debug output
*
* @var string
* @access private 
*/
 	public $VERSION		= "EcTemplate v2";

/**
* Loaded templates.
*
* @var array
* @access private 
*/
 	public $TEMPLATE		= array();

/**
 * Storing the handels to the loaded templates.
 *
 * @var array
 * @access private
 */
 	public $TEMPLATEHANDLE	= array();

/**
 * Description: Handels to the loaded templates.
 *
 * @var array
 * @access private
 */
 	public $HANDLE			= array();

/**
 * Handels to the parsed templates or blocks.
 *
 * @var array
 * @access private
 */
 	public $PARSED			= array();

/**
 * Assigned variables in the template(s).
 *
 * @var Array
 * @access private
 */
 	public $ASSIGNVAR		= array();

/**
 * Assigned variables alias names.
 *
 * @var Array
 * @access private
 */
 	public $VARALIAS		= array();

/**
 * Assigned replacements.
 *
 * @var array
 * @access private
 */
 	public $ASSIGNREPLACE	= array();

/**
 * Found variables in the template(s).
 *
 * @var Array
 * @access private
 */
 	public $FOUNDVAR		= array();
 	 	
/**
 * Found variables in the template(s).
 *
 * @var Array
 * @access private
 */
 	public $UNASSIGNED		= array(); 	
 	
/**
 * The directory containing the templates.
 *
 * @var string
 * @access private
 */
 	public $FILEROOT		=	"";

/**
 * Block start definition, must always contain % for macro replacement.
 *
 * @var string
 * @access private
 */
 	public $BLOCKSTART		= "<!-- #BLOCK-START:% -->";

/**
 * Block end definition, must always contain % for macro replacement.
 *
 * @var string
 * @access private
 */
 	public $BLOCKEND		= "<!-- #BLOCK-END:% -->";

/**
 * Open tag for assigning variable.
 *
 * @var string
 * @access private
 */
 	public $OPENTAG		= "[%";

/**
 * Close tag for assigning variable.
 *
 * @var string
 * @access private
 */
 	private  $CLOSETAG		= "%]";

/**
 * Error message.
 *
 * @var String
 * @access private
 */
 	public $ERROR			= "";

 	
 /**
 * removing new line chars in output
 *
 * var boolean
 * access private			
 *
 */
 public $PARSE_CONST		= true;
 	
 /**
 * removing new line chars in output
 *
 * var boolean
 * access private			
 *
 */
 public $REMOVE_CR			= false;

/**
* The constructor for creating a new instance of the ecTemplate class
*
* When no $fileRoot argument is given $fileRoot gets the default value "./" (Unix based current dir)
*
* @param string The template root directory
* @return void
* @access public
*   
*/
 	function __construct ($fileRoot = "./")
	{
		$this->setTags($this->OPENTAG,$this->CLOSETAG);
		
		if (!is_dir($fileRoot))
		{
			$this->_error("EcTemplate2(string fileRoot)",
				"illegal path [$fileRoot].",1);
		}
		$this->FILEROOT = $fileRoot;			
	}

/**
* Sets the directory holding the templates
*
* While creating a instance of the EcTemplate object a template root directory
* is set. The default directory is the current directory. With this function it's
* possible to change it at a later phase
*
* @param string The dir containing the templates
* @return void
* @access public
*/
 	function setFileRoot ($fileRoot)
	{
		if (!is_dir($fileRoot))
		{
			$this->_error("setFileRoot(string fileRoot)", "illegal path [$fileRoot].",1);
		}
		$this->FILEROOT = $fileRoot;
	}

/**
* Sets the open and close tags that are used in the template.
*
* Use this function to change the current open and close tag definition for
* template variables. Default open and close tags are { and }. This means that
* EcTempate replaces variable like {VAR}. for example use setTags("<[","]>")
* to use variable replacement like <[VAR]>
*
* @param string The var opentag definition
* @param string Thhe var closetag definition
* @access public 
* @return void 
*/
 	function setTags($open, $close)
	{
		$this->OPENTAG = preg_quote($open);
		$this->CLOSETAG = preg_quote($close);
		// unquoted used for placing back the tags after a load block
		$this->_OPENTAG = $open;
		$this->_CLOSETAG = $close;		
	}

/**
* Loads a template
*
* Here we can load a template. Use the $handle parameter to specify a handle to the loaded template. 
* If you are planning to only load one template you don't need to specify a template handle. 
* if you planning to load more templates only the first template can be loaded without using 
* the handle parameter.
*
* @param string The file to load
* @param string A handle name. This is optional, if no handle is given the file name will be the handle name
* @return void 
* @access public 
*/
 	function loadTemplate($fileName, $handle=false)
	{
		if (is_numeric($handle))
		{
			$this->_error("loadTemplate(fileName,[handle])", "The handle can not be a numeric value",1);
		}
		if ( (sizeof($this->TEMPLATE) > 0) && empty($handle))
		{
			$this->_error("loadTemplate(fileName,[handle])", "Only the first template can be loaded without a template handle. use: loadTemplate(fileName,handle)",1);
		}
		$this->TEMPLATE[] = $fileName;
//		$this->TEMPLATEHANDLE[] = $handle;
		$this->HANDLE[($handle) ? $handle : $fileName] = $this->_readTemplate($fileName);
	}

/**
* Loads a string as if it was a template
*
* Here we can load a string. Use the $handle parameter to specify a handle to the loaded string as refer to use de data. 
* If you are planning to only load one string you don't need to specify a handle. 
* if you planning to load more strings only the first template can be loaded without using 
* the handle parameter.
*
* @param string the content
* @param string A handle name. This is optional, if no handle is given the file name will be the handle name
* @return void 
* @access public 
*/
 	function loadTemplateString($str, $handle=false)
	{
		if (is_numeric($handle))
		{
			$this->_error("loadTemplateString(str,[handle])", "The handle can not be a numeric value",1);
		}
		if ( (sizeof($this->TEMPLATE) > 0) && empty($handle))
		{
			$this->_error("loadTemplateString(str,[handle])", "Only the first string can be loaded without a handle. use: loadTemplateString(str,handle)",1);
		}
		$this->TEMPLATE[] = ($handle) ? $handle : '[ect_unnamed_template_string]';
		$this->HANDLE[($handle) ? $handle : '[ect_unnamed_template_string]'] = $str;		
	}	
	
/**
* load a data block 
*
* Load a data block from a loaded template or a other loaded block. Use the optional $handle param 
* to specified in what loaded data EcTemplate should look for the block. 
* When using without a handle EcTemplate will search for the block in the first loaded template. 
* When using an array as $block parameter EcTemplate expects a key => value array where the key holds the name and the value holds the handle of each block.
*
* @param mixed The name of the block to load or the array of blocks to load.
* @param string The handle to the loaded data from which the block sould be loaded
* @return void 
* @access public
*   
*/
 	function loadBlock($block,$handle=false)
	{
		// array could be like array('row','column' => 'TEMPLATEHANDLE')
		// if $name is empty the $key hold the $block
		// if $name not empty then $name holds the $block and $key the templateHandle
		if (is_array($block))
		{
			foreach ($block as $key => $val)
			{
				(is_numeric($key)) ? $this->_loadBlock($val) : $this->_loadBlock($key,$val);
			}
		} else
		{
			$this->_loadBlock($block, $handle);
		}
	}

/**
* Drops a data block
*
* Drops a block from a loaded template or a previous loaded data block. 
* If no handle is used EcTemplate will search for the block in the first loaded template
*
* @param string The block name
* @param string The handle to the template data that contains the block
* @return void 
* @access public
*/
 	function dropBlock($block, $handle=false)
	{
		$opentag = str_replace("%", $block, $this->BLOCKSTART);
		$closetag = str_replace("%", $block, $this->BLOCKEND);

		$handle = ($handle) ? $handle : $this->TEMPLATE[0];

		if (empty($this->HANDLE[$handle]))
		{
			$this->_error("dropBlock(block,[handle])", "no template data found at handle [$handle].",1);
		}
		else
		{
			$this->HANDLE[$handle] = preg_replace('/'.$opentag.'(.*)'.$closetag.'/sm', false, $this->HANDLE[$handle]);
		}
	}

/**
* Assign template variable
*
* Assiging actually template variable. 
* if the first arg is not a array this function assumes the first arg
* is the template variable name and the second is the value
*
* @param mixed When using a string it represents the name variable name. When using a associated array the array key represents the variable name and the array value represents the variable value
* @param string The value of the template variable
* @return void 
* @access public
*/
 	function assign($name,$val=false)
	{
		if (is_array($name) && !$val)
		{
			foreach($name as $key => $val)
			{
				$this->ASSIGNVAR[$key] = $val;
			}
			return;
		}
		$this->ASSIGNVAR[$name] = $val;
	}

/**
* Assign template variable and append it on allready assigned data
*
* Assiging actually template variable. but if there is allready data under the assigned name, the new data is appended on the old data
* if the first arg is not a array this function assumes the first arg
* is the template variable name and the second is the value
*
* @param mixed When using a string it represents the name variable name. When using a associated array the array key represents the variable name and the array value represents the variable value
* @param string The value of the template variable
* @return void 
* @access public
*/
 	function assignAppend($name,$val=false)
	{
		if (is_array($name) && !$val)
		{
			foreach($name as $key => $val)
			{
				$this->ASSIGNVAR[$key] .= $val;
			}
			return;
		}
		$this->ASSIGNVAR[$name] .= $val;
	}

/**
* Create a alias for a assigned var
*
* @param string The name of the assigned var where you want to create te alias for
* @param string The alias name
* @return void 
* @access public
*/
 	function assignAlias($name,$alias)
	{
		if (empty($this->ASSIGNVAR[$name]))
		{
			$this->_error("assignAlias(name,alias)", "Can not create alias [$alias] for non-existing var [$name].",1);
		}
		if (isset($this->ASSIGNVAR[$alias])) $this->assignAppend($alias,$this->ASSIGNVAR[$name]);
		else $this->assign($alias,$this->ASSIGNVAR[$name]);
	}

/**
* Checks if a assigned variable is empty
*
* Checks if a assigned variable is empty. This could come in handy when you're assign var that 
* (for example) came from a database query
*
* @param string The template var to check
* @return boolean Whether or not the assigned template variable is empty
* @access public
*/
 	function isAssignedEmpty($key)
	{
		return empty($this->ASSIGNVAR[$key]);
	}

/**
* Returning the value of a assigned variable
*
* Getting the value of a variable assigned in a previous action. What more can I say?
*
* @param string The variable name you want get
* @return string The value of a assigned variable or false if none found
* @access public
*/
 	function getAssigned($key) {

		return $this->ASSIGNVAR[$key];
	}

/**
* assign replacement
*
* Assign replacements for a parsed template. 
* For example assignReplace('EcTemplate','<b>EcTemplate</b>'); 
* This way we make every tekst EcTemplate bold
*
* if an array is passed, all key -> values will be build.
* if the first arg is not a array this function assumes the first arg
* is the text that needs to be replaces with the value of the second arg
*
* @param mixed The text to replace or when using a associated array the key represents the tekst that should be replaced and the array value represents the text to replace it with
* @param string the replace value
* @return void 
* @access public
*/
 	function assignReplace($name, $val=false)
	{
		if (is_array($name) && !$val)
		{
			foreach($name as $key => $val)
			{
				$this->ASSIGNREPLACE[$key] = $val;
			}
			return;
		}
		$this->ASSIGNREPLACE[$name] = $val;
	}

/**
* Get the parsed template or block
*
* Get the parsed template data or block data. Usefull for assigning a complate parsed block 
* (or template) to another template variable.
* If no templateHandle is given, the first parsed template data is returned
*
* @param string If no parameter is used EcTemplate looks in the first loaded template
* @return string The string of the parsed template, block or false if none found
* @access public
*/
 	function getParsed($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];
		if ($this->REMOVE_CR) $this->PARSED[$handle] = preg_replace("(\r\n|\n|\r)", "", $this->PARSED[$handle]);
		return $this->PARSED[$handle];
	}

/**
* Clears the parsed data at a given handle
*
* Clears the parsed data in a given handle or at the first loaded template and parsed template. 
* Usefull when working with blocks in blocks. if handle is given, 
* the first parsed template will be cleared
*
* @param string The handle to the data to clear
* @return void 
* @access public
*/
 	function clearParsed($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];

		if (empty($this->HANDLE[$handle])) {
			$this->_error("clearParsed([string handle])", "handle not found for [$handle]",1);
		}
		unset($this->PARSED[$handle]);
	}
	
/**
* Clears the assigned vars
*
* @return void 
* @access public
*/
 	function clearAssigned()
	{
		$this->ASSIGNVAR = array();
	}	

/**
* Parses a loaded template or block
*
* Parse a loaded template or block. 
* Here the actually template variables are replaced with there values
*
* @param string The handle of the data that needs to be parsed. If no handle is given the first loaded template is parsed
* @return void 
*/
 	function parse($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];
		$this->PARSED[$handle] = $this->_parse($handle);
	}

/**
 * Parses a template or block and append the result on itself
 *
 * Parses a template (unlikly) or a block (likly) and append the result on itself. 
 * this way you can loop data.
 *
 * @param string The handle to the data to parseAppend
 * @access public
 * @see parse getParsed
 */
 	function parseAppend($handle)
	{
		$this->PARSED[$handle] .= $this->_parse($handle);
	}

/**
* Parse assigned replacements on a allready parsed block or template
*
* replaces text matching the key's with the values of that key in the template
* key's and values should be allready listed in the ASSIGNREPLACE array
* if no template handle is given the first loaded template is used
*
* @param $templateHandle string
* @access public
*/
 	function parseReplace($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];

		if (empty($this->PARSED[$handle])) {
			$this->_error("parseReplace(string handle)", "handle not found [$handle], is it parsed yet?",1);
		}
		while (list($key, $val) = each ($this->ASSIGNREPLACE)) {
			$this->PARSED[$handle] = str_replace($key, $val, $this->PARSED[$handle]);
		}
	}

/**
* Enable or disable contants parsing
*
* enabling parsing of php constant [ defined('SOMECONSTANT','the value') ] will parse template var {SOMECONSTANT}
* This could come in handy when building apps in more then one languages ;)
*
* @param boolean
* @access public
*/
 	function parseConstants($state=true)
	{
		$this->PARSE_CONST=$state;
	}


/**
* Enable or disable outputting without new line chars
*
* When enabled will output the parsed 
* data as one string without line feeds
*
* @param boolean
* @access public
* @see show
*/
 	function removeNewLines($state=true)
	{
		$this->REMOVE_CR = $state;
	}	
	
/**
 * Outputs the parsed data to the browser
 *
 *
 * @param string the handle to the parsed data, if no handle given the first parsed template is shown
 * @access public
 * @see getParsed
 */
 	function show($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];
		
		if (empty($this->PARSED[$handle]) && $handle)
		{
			$this->_error("show(string handle)", "nothing to show for [$handle]",1);
		}
		
		print $this->getParsed($handle);
	}
	
/**
 * Short for Parse and Show
 *
 *
 * @param string the handle to the parsed&show data, if no handle given the first template is parsed&shown
 * @access public
 * @see parse 
 * @see show 
 */	
	function showParsed($handle=false)
	{
		$this->parse($handle);
		$this->show($handle);
	}

/**
* returns the unparsed template.
*
* if no templateHandle is given the first loaded template is returned.
* notice that if a block is allready loaded from the template that this block is replaced with 
* the template var definition
*
* @param string the handle to the loaded template, if no handle is given the first loaded template is returned
* @return string
* @access public
*/
 	function getTemplate($handle=false)
	{
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];

//		if (is_numeric($handle)) $handle = $this->TEMPLATEHANDLE[$handle];

		if (empty($this->HANDLE[$handle]) && $handle)
		{
			$this->_error("getTemplate(string handle)", "nothing to get for [$templateHandle]",1);
		}
		return $this->HANDLE[$handle];
	}

/**
* returns the found template vars.
*
* @return array
* @access public
*/	
	function getTemplateVars()
	{
		return $this->FOUNDVAR;
	}	

/**
 * showing debug infomation
 *
 * Shows debug information of the current state of the EcTemplate object. Can by handy sometimes
 *
 * @access public
 */
 	function debug() 
 	{
		$unique_token = md5(uniqid(rand(), true));
		echo "<table width=\"80%\" align=\"center\" border=\"1\" bordercolor=\"#000000\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"FFFFFF\">\n";
		echo "<tr><td bgcolor=\"#000000\"><b><font color=\"#FFFFFF\">".$this->VERSION." debug infomation</font></b></td></tr>\n";

		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_templates_tags');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">Template tags</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		echo "<div id=\"".$unique_token."_ect_templates_tags\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		echo "<tr><td><b>Var open tag : </b>".htmlentities($this->OPENTAG)."<br>\n";
		echo "<b>Var close tag : </b>".htmlentities($this->CLOSETAG)."<br>\n";
		echo "<b>Block start tag : </b>".htmlentities($this->BLOCKSTART)."<br>\n";
		echo "<b>Block end tag : </b>".htmlentities($this->BLOCKEND)."</td></tr>\n";
 		echo "</table></td></tr>\n";	

		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_templates_fileroot');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">Fileroot</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		echo "<div id=\"".$unique_token."_ect_templates_fileroot\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		echo "<tr><td>".htmlentities($this->FILEROOT)."</td></tr>\n";
 		echo "</table></td></tr>\n";		
		
		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_templates');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->TEMPLATE)." loaded template file(s) (Template handle => filename)</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->TEMPLATE);
		echo "<div id=\"".$unique_token."_ect_templates\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		foreach ($this->TEMPLATE as $key => $value) {
			echo "<tr><td bgcolor=\"#FFFFFF\"><font color=\"#000000\">".nl2br(htmlentities($key))." => ".$this->FILEROOT.$value."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";			
		
		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_templates_data');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->HANDLE)." loaded template(s) data</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->HANDLE);
		echo "<div id=\"".$unique_token."_ect_templates_data\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		foreach ($this->HANDLE as $key => $value) {
			echo "<tr><td bgcolor=\"#CCCCCC\">".$key."</td></tr>\n";
			echo "<tr><td><font color=\"#000000\">".nl2br(htmlentities($value))."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";			
		
		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_assignedvars');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->ASSIGNVAR)." assigned var(s)</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->ASSIGNVAR);
		echo "<div id=\"".$unique_token."_ect_assignedvars\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		while (list ($key, $value) = each ($this->ASSIGNVAR)) {
		echo "<tr><td bgcolor=\"#CCCCCC\">".$key."</td></tr>\n";			
			if ($this->isAssignedEmpty($key)) {
				echo "<tr><td><font color=\"#CC3300\">< No value ></font></td></tr>\n";
			} else {
				echo "<tr><td><font color=\"#000000\">".nl2br(htmlentities($value))."</font></td></tr>\n";
			}
 		}
 		echo "</table></td></tr>\n";			

		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_assignreplace');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->ASSIGNREPLACE)." assigned replacements</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->ASSIGNREPLACE);
		echo "<div id=\"".$unique_token."_ect_assignreplace\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		while (list ($key, $value) = each ($this->ASSIGNREPLACE)) {
			echo "<tr><td><font color=\"#000000\">".$key." - ".nl2br(htmlentities($value))."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";		

		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_foundvar');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->FOUNDVAR)." template vars found</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->FOUNDVAR);
		echo "<div id=\"".$unique_token."_ect_foundvar\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		while (list ($key, $value) = each ($this->FOUNDVAR)) {
			echo "<tr><td><font color=\"#000000\">".$key." - ".nl2br(htmlentities($value))."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";

		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_unassigned');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->UNASSIGNED)." unassigned template vars</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->UNASSIGNED);
		echo "<div id=\"".$unique_token."_ect_unassigned\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		while (list ($key, $value) = each ($this->UNASSIGNED)) {
			echo "<tr><td><font color=\"#000000\">".$key." - ".nl2br(htmlentities($value))."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";		


		echo "<tr><td bgcolor=\"#999999\" onclick=\"javascript:var e=getElementById('".$unique_token."_ect_parsed');e.style.display=(e.style.display=='none')?'':'none';\"><b><font color=\"#FFFFFF\">".count($this->PARSED)." parsed item(s)</font></b></td></tr>\n";
		echo "<tr><td bgcolor=\"#FFFFFF\">";		
		reset($this->PARSED);
		echo "<div id=\"".$unique_token."_ect_parsed\" style=\"display:None\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"1\" bordercolor=\"CCCCCC\">";
		foreach ($this->PARSED as $key => $value) {
			echo "<tr><td bgcolor=\"#CCCCCC\">".$key."</td></tr>\n";
			echo "<tr><td><font color=\"#000000\">".nl2br(htmlentities($value))."</font></td></tr>\n";
 		}
 		echo "</table></td></tr>\n";		
	}


	/*---------------------------------------------------------*\
	|				PRIVATE FUNCTIONS (INTERNAL USE)						|
	\*---------------------------------------------------------*/

/**
 * reads the template from filesystem
 *
 * Reads a template from filesystem and returns it as one (big) string.
 *
 * @param String the filename
 * @return string
 * @access private
 */
 	function _readTemplate($fileName)
	{
		if(!is_file($this->FILEROOT.$fileName))
		{
			$this->_error("_readTemplate(string fileName)", "illegal file path [$this->FILEROOT$fileName].",1);
		}
		$content = implode(false,@file($this->FILEROOT.$fileName));
		if(empty($content))
		{
			$this->_error("getTemplate(string fileName)", "file is empty [$fileName].",1);
		}

		return $content;
	}


/**
 * Loads a block.
 *
 * Loads a block from a template or block. The loaded block name becomes a variable definition in the old template or block
 * @param String The block name
 * @param String The handle to the data where the block is located in.
 * @access private
 */
 	function _loadBlock($name,$handle=false)
	{
		if (is_numeric($name))
		{
			$this->_error("loadBlock(blockName,[templateHandle])", "blockName can not be numeric.",1);
		}
		$opentag = str_replace("%", $name, $this->BLOCKSTART);
		$closetag = str_replace("%", $name, $this->BLOCKEND);

		// if no handle is given we get the fist loaded template
		$handle = ($handle) ? $handle : $this->TEMPLATE[0];

		if (empty($handle))
		{
			$this->_error("loadBlock(loopName,[handle])", "loop handle not found[$name].",1);
		}
		elseif (empty($this->HANDLE[$handle]))
		{
			$this->_error("loadBlock(loopName,[handle])", "no template data found at handle [$handle].",1);
		}
		else
		{
			$new_template = preg_replace('/.*'.$opentag.'(.*)'.$closetag.'.*/sm', '\\1',$this->HANDLE[$handle]);
			$modified_template = preg_replace('/'.$opentag.'(.*)'.$closetag.'/sm', $this->_OPENTAG.$name.$this->_CLOSETAG, $this->HANDLE[$handle]);

			$this->HANDLE[$name] = $new_template;
			$this->HANDLE[$handle] = $modified_template;
		}
	}

/**
 * Parses the template
 *
 * parses a template (does the actually replace of the template definitions)
 *
 * @param String the handle name of the data to parse
 * @access private
 * @return string
 */
 	function _parse($handle)
	{
		if (empty($this->HANDLE[$handle])) {
			$this->_error("parse([string handle])", "nothing to parse for [$handle]",1);
		}
		return preg_replace("/".$this->OPENTAG."(.*)".$this->CLOSETAG."/Ue", "\$this->_lookup('\\1')", $this->HANDLE[$handle]);
	}

/**
 * looks up the the value for the found template var
 * 
 * @return string The value for the given var name or false if none is found
 * @access private
 * @param string the name of the found var
 *
 */
 	function _lookup($name)
	{
		$this->FOUNDVAR[] = $name;
		if (isset($this->ASSIGNVAR[$name])) return $this->ASSIGNVAR[$name];
		if ($this->PARSE_CONST && defined($name)) return constant($name);
		$this->UNASSIGNED[$name] = $name;
		return false;
	}

/**
* Error outputting
*
* Just showing messages if you do stupid things ;)
*
* @param String function name
* @param String The error message
* @param integer Whether or not the script should die
* @return void 
* @access private
*/
 	function _error($functionName, $errorMsg, $die = 0)
	{
		$this->ERROR = $functionName." ".$errorMsg;
		echo "ERROR: ".$this->ERROR."<BR>\n";
		if ($die == 1)
		{
		  exit;
		}
	}
}
?>
